package com.bt7274.service.impl;

import co.elastic.clients.elasticsearch.security.UserProfile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bt7274.enums.PermissionGroupEnum;
import com.bt7274.enums.UserStatusEnum;
import com.bt7274.exception.BusinessException;
import com.bt7274.mapper.InvitationCodeMapper;
import com.bt7274.mapper.PromotionPolicyMapper;
import com.bt7274.mapper.PromotionPolicyMapper;
import com.bt7274.mapper.UserExpMapper;
import com.bt7274.pojo.InvitationCode;
import com.bt7274.pojo.PromotionPolicy;
import com.bt7274.pojo.PromotionPolicy;
import com.bt7274.pojo.UserExp;
import com.bt7274.pojo.bo.*;
import com.bt7274.pojo.vo.PageResult;
import com.bt7274.pojo.vo.UserCheckInVO;
import com.bt7274.pojo.vo.UserExpVO;
import com.bt7274.pojo.vo.UserInfoVO;
import com.bt7274.mapper.UserMapper;
import com.bt7274.pojo.User;
import com.bt7274.service.PermanentPromotionService;
import com.bt7274.service.UserService;
import com.bt7274.utils.PasswordUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import static com.bt7274.exception.GraceExceptionHandler.log;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.math.BigDecimal;
import com.bt7274.config.MinIOConfig;
import com.bt7274.base.MinIOUtil;


/**
 * @Data 2025/3/25 02:17
 * @Author hp
 * @Version 1.0
 * @Description UserServiceImpl
 */

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private PromotionPolicyMapper promotionPolicyMapper;


    @Resource
    private UserMapper userMapper;
    @Resource
    private UserExpMapper userExpMapper;

    @Resource
    private InvitationCodeMapper invitationCodeMapper;

    @Resource
    private PasswordUtils passwordUtils;

    @Resource
    private PermanentPromotionService permanentPromotionService;

    @Resource
    private MinIOConfig minIOConfig;

    private LocalDateTime localDateTime = LocalDateTime.now();

    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public void createOrUpdate(UserBO userBO) {
        User user = new User();
        BeanUtils.copyProperties(userBO, user); //将userBO中的属性复制到user中
        user.setUpdatedTime(LocalDateTime.now());
        if(StringUtils.hasText(user.getId())){
            user.setCreatedTime(LocalDateTime.now());
            userMapper.insert(user);
        }else{
            userMapper.updateById(user);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserInfoVO register(UserRegisterBO userRegisterBO){
        //进行参数校验
        validateRegisterParams(userRegisterBO);

        //检查用户名和邮箱是否已存在
        if (existsByUsername(userRegisterBO.getUsername())) {
            throw new BusinessException("用户名已存在");
        }
        if (existsByEmail(userRegisterBO.getEmail())) {
            throw new BusinessException("邮箱已存在");
        }

        //处理邀请码
        String invitedBy = null;
        Integer permissionGroup = PermissionGroupEnum.INTERN.getCode();//默认为见习生
        if (StringUtils.hasText(userRegisterBO.getInvitationCode())){
            InvitationCode invitationCode = validateInvitationCode(userRegisterBO.getInvitationCode());
            invitedBy = invitationCode.getCreateBy();
            permissionGroup = PermissionGroupEnum.GRADUATE.getCode();

            //标记邀请码为已使用
            invitationCodeMapper.markAsUsed(invitationCode.getId(), null); //暂时写null，之后再更新
        }
        String encodedPassword = passwordUtils.encode(userRegisterBO.getPassword());
        // 创建用户
        User user = new User();
        user.setId(UUID.randomUUID().toString().replace("-", ""));
        BeanUtils.copyProperties(userRegisterBO, user);
        user.setPassword(encodedPassword);
        //user.setPasskey(generatePasskey(user.getId()));
        user.setPasskey(UUID.randomUUID().toString());
        user.setPermissionGroup(permissionGroup);
        user.setInvitedBy(invitedBy);
        user.setStatus(UserStatusEnum.NORMAL.getCode());
        user.setCreatedTime(localDateTime);
        user.setUpdatedTime(localDateTime);

        //保存用户
        userMapper.insert(user);

        // 初始化用户体验数据
        UserExp userExp = new UserExp();
        userExp.setId(user.getId());
        userExp.setUploaded(0L);
        userExp.setDownloaded(0L);
        userExp.setRatio(BigDecimal.valueOf(0.0f));
        userExp.setExperience(0);
        userExp.setBt(0);
        userExp.setUpdatedTime(localDateTime);
        userExpMapper.insert(userExp);

        //若使用了邀请码，则更新使用者信息
        if (StringUtils.hasText(userRegisterBO.getInvitationCode())){
            InvitationCode invitationCode = invitationCodeMapper.selectByCode(userRegisterBO.getInvitationCode());
            invitationCodeMapper.markAsUsed(invitationCode.getId(), user.getId());
        }

        log.info("用户注册成功，用户ID：{}, 用户名：{}",user.getId(),user.getUsername());
        //返回用户信息
        return convertToUserInfoVO(user);
    }


    @Override
    public UserInfoVO login(UserLoginBO userLoginBO) {
        //  登录时参数校验
        if (!StringUtils.hasText(userLoginBO.getUsernameOrEmail()) ||
                !StringUtils.hasText(userLoginBO.getPassword())) {
            throw new BusinessException("用户名和密码不能为空");
        }

        //  查找用户，判断用户是否存在
        User user = findByUsernameOrEmail(userLoginBO.getUsernameOrEmail());
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 若用户存在，检查用户账号状态
        if (UserStatusEnum.BANNED.getCode().equals(user.getStatus())) {
            throw new BusinessException("账户已被封禁");
        }

        // 验证密码是否正确
        if (!verifyPassword(user, userLoginBO.getPassword())) {
            throw new BusinessException("密码错误");
        }

        // 更新登录时间
        user.setUpdatedTime(LocalDateTime.now());
        userMapper.updateById(user);

        // 执行签到
        try {
            UserCheckInBO checkInBO = new UserCheckInBO();
            checkInBO.setUserId(user.getId());
            permanentPromotionService.dailyCheckIn(checkInBO);
            log.info("用户签到成功");
        } catch (Exception e) {
            log.error("用户签到失败: {}", e.getMessage(), e);
            // 签到失败不影响登录流程
        }

        log.info("用户登录成功，用户ID: {}, 用户名: {}", user.getId(), user.getUsername());

        //  返回用户信息
        return convertToUserInfoVO(user);
    }

    @Override
    public boolean updatePassword(UserProfileUpdateBO userProfileUpdateBO){
        User user = findByUsernameOrEmail(userProfileUpdateBO.getEmail());
        if (!verifyPassword(user, userProfileUpdateBO.getOldPassword())) {
            throw new BusinessException("原始密码不正确");
        }else {
            user.setPassword(passwordUtils.encode(userProfileUpdateBO.getNewPassword()));
        }

        //  更新修改时间
        user.setUpdatedTime(LocalDateTime.now());
        userMapper.updateById(user);
        return true;
    }
    @Override
    public UserInfoVO getUserInfo(String userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        return convertToUserInfoVO(user);
    }

    @Override
    public UserExpVO getUserExp(String userId) {
        UserExp userExp = userExpMapper.selectById(userId);
        if (userExp == null) {
            throw new BusinessException("用户体验数据不存在");
        }
        return convertToUserExpVO(userExp);
    }


    @Override
    public boolean existsByUsername(String username) {
        return userMapper.selectByUsername(username) != null;
    }

    @Override
    public boolean existsByEmail(String email) {
        return userMapper.selectByEmail(email) != null;
    }

    @Override
    public User findByUsernameOrEmail(String usernameOrEmail) {
        return userMapper.selectByUsernameOrEmail(usernameOrEmail);
    }

    @Override
    public boolean updateStatus(String userId, Integer status) {
        return userMapper.updateStatus(userId,status)>0;
    }

    @Override
    public boolean updatePermissionGroup(String userId, Integer permissionGroup) {
        return userMapper.updatePermissionGroup(userId,permissionGroup) > 0;
    }

    @Override
    public boolean banUser(String userId) {
        return updateStatus(userId, UserStatusEnum.BANNED.getCode());
    }

    @Override
    public boolean unbanUser(String userId) {
        return updateStatus(userId, UserStatusEnum.NORMAL.getCode());
    }

    /**
     * 注册参数校验
     */
    private void validateRegisterParams(UserRegisterBO userRegisterBO){
        if (!userRegisterBO.getPassword().equals(userRegisterBO.getConfirmPassword())) {
            throw new BusinessException("两次输入的密码不一致");
        }
    }

    /**
     * 验证邀请码
     */
    private InvitationCode validateInvitationCode(String code) {
        InvitationCode invitationCode = invitationCodeMapper.selectValidCode(code, localDateTime);
        if (invitationCode == null) {
            throw new BusinessException("邀请码无效或已过期");
        }
        if (StringUtils.hasText(invitationCode.getUsedBy())) {
            throw new BusinessException("邀请码已被使用");
        }
        return invitationCode;
    }

    /**
     * 转换为用户信息VO
     */
    private UserInfoVO convertToUserInfoVO(User user) {
        UserInfoVO vo = new UserInfoVO();
        BeanUtils.copyProperties(user, vo);
        vo.setPermissionGroupName(PermissionGroupEnum.getByCode(user.getPermissionGroup()).getName());
        return vo;
    }

    /**
     * 转换为用户经验VO
     */
    private UserExpVO convertToUserExpVO(UserExp userExp) {
        UserExpVO vo = new UserExpVO();
        BeanUtils.copyProperties(userExp, vo);
        return vo;
    }

    @Override
    public String generatePasskey(String userId) {
        String uuid1 = UUID.randomUUID().toString().replace("-", "");
        String uuid2 = UUID.randomUUID().toString().replace("-", "");
        return (uuid1 + uuid2).substring(0, 64);
    }

    @Override
    public boolean verifyPassword(User user, String password) {
        return passwordUtils.matches(password, user.getPassword());
    }

    @Override
    public PageResult<UserInfoVO> queryUserList(UserQueryParam param) {
        // 设置分页参数
        PageHelper.startPage(param.getPageNum(), param.getPageSize());

        // 构建查询条件
        User queryUser = new User();
        if (StringUtils.hasText(param.getUsername())) {
            queryUser.setUsername(param.getUsername());
        }
        if (StringUtils.hasText(param.getEmail())) {
            queryUser.setEmail(param.getEmail());
        }
        if (param.getPermissionGroup() != null) {
            queryUser.setPermissionGroup(param.getPermissionGroup());
        }
        if (param.getStatus() != null) {
            queryUser.setStatus(param.getStatus());
        }

        // 执行查询
        List<User> userList = userMapper.selectUserList(queryUser);

        // 获取分页信息
        PageInfo<User> pageInfo = new PageInfo<>(userList);

        // 转换为VO对象
        List<UserInfoVO> userInfoVOList = userList.stream()
                .map(this::convertToUserInfoVO)
                .collect(Collectors.toList());

        // 构建返回结果
        PageResult<UserInfoVO> pageResult = new PageResult<>();
        pageResult.setTotal(pageInfo.getTotal());
        pageResult.setCurrent(param.getPageNum());
        pageResult.setSize(param.getPageSize());
        pageResult.setRecords(userInfoVOList);

        return pageResult;
    }

    @Override
    public UserInfoVO updateUserProfile(UserProfileBO userProfileBO) {
        // 验证用户是否存在
        User existUser = userMapper.selectById(userProfileBO.getId());
        if (existUser == null) {
            throw new BusinessException("用户不存在");
        }

        // 检查用户名是否被其他用户使用
        if (StringUtils.hasText(userProfileBO.getUsername())
        && !userProfileBO.getUsername().equals(existUser.getUsername())) {
            User userWithSameUsrname = userMapper.selectByUsername(userProfileBO.getUsername());
            if (userWithSameUsrname != null) {
                throw new BusinessException("用户名已被使用");
            }
        }

        //检查邮箱是否被其他用户使用
        if (StringUtils.hasText(userProfileBO.getEmail())
        && !userProfileBO.getEmail().equals(existUser.getEmail())) {
            User userWithSameEmail = userMapper.selectByEmail(userProfileBO.getEmail());
            if (userWithSameEmail != null) {
                throw new BusinessException("邮箱已被使用");
            }
        }

        // 更新用户信息
        User user = new User();
        user.setId(userProfileBO.getId());

        if (StringUtils.hasText(userProfileBO.getUsername())) {
            user.setUsername(userProfileBO.getUsername());
        }

        if (StringUtils.hasText(userProfileBO.getEmail())) {
            user.setEmail(userProfileBO.getEmail());
        }

        // 处理头像上传
        if (userProfileBO.getAvatarFile() != null && !userProfileBO.getAvatarFile().isEmpty()) {
            try {
                String filename = userProfileBO.getAvatarFile().getOriginalFilename();
                if (StringUtils.hasText(filename)) {
                    filename = "avatar/" + UUID.randomUUID().toString() + filename.substring(filename.lastIndexOf("."));
                    String avatarUrl = MinIOUtil.uploadFile(minIOConfig.getBucketName(), filename, userProfileBO.getAvatarFile().getInputStream(), true);
                    user.setAvatarUrl(avatarUrl);
                }
            } catch (Exception e) {
                log.error("头像上传失败: {}", e.getMessage(), e);
                throw new BusinessException("头像上传失败");
            }
        } else if (StringUtils.hasText(userProfileBO.getAvatarUrl())) {
            user.setAvatarUrl(userProfileBO.getAvatarUrl());
        }

        user.setUpdatedTime(LocalDateTime.now());

        // 更新用户
        userMapper.updateById(user);

        // 查询更新后的用户信息
        User updatedUser = userMapper.selectById(userProfileBO.getId());
        log.info("用户信息更新成功，用户ID: {}, 用户名: {}", updatedUser.getId(), updatedUser.getUsername());

        // 返回更新后的用户信息
        return convertToUserInfoVO(updatedUser);
    }


    @Override
    public User getUserById(String id) {
        return userMapper.selectById(id);
    }


    @Override
    public String getPasskeyById(String id) {
        User user = userMapper.selectOne(
                new QueryWrapper<User>().eq("id", id)
        );
        return user.getPasskey();
    }



    @Override
    public User getUserByPasskey(String passkey) {
        return userMapper.selectOne(
                new QueryWrapper<User>().eq("passkey", passkey)
        );
    }

    @Override
    public long calculatePromotionUploadOffset(String userId, long lastDownload) {
        UserExp userExp = userExpMapper.selectById(userId);
        if (userExp == null) {
            return 0;
        }
        PromotionPolicy promotionPolicy = promotionPolicyMapper.selectById(userExp.getPromotionPolicyId());
        if (promotionPolicy == null) {
            return 0;
        }
        return (long) promotionPolicy.applyUploadRatio(lastDownload);
    }

    @Override
    public long calculatePromotionDownloadOffset(String userId, long lastUploaded) {
        UserExp userExp = userExpMapper.selectById(userId);
        if (userExp == null) {
            return 0;
        }
        PromotionPolicy promotionPolicy = promotionPolicyMapper.selectById(userExp.getPromotionPolicyId());
        if (promotionPolicy == null) {
            return 0;
        }
        return (long) promotionPolicy.applyDownloadRatio(lastUploaded);
    }
}
